// Copyright (C) 2008 Taylor L. Riche <riche@cs.utexas.edu>
//  
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
// 
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software 
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
//

package syscomp.entities;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintStream;
import java.net.URI;

import core.CodeGenerator;
import core.Entity;


public class CommChannel extends Entity {
	private final int bandwidth;
	private final int latency;
	private final String core;
	private final String put;
	private final String get;
	private final String empty;
	private final String sinkProc;
	private final String chanMtx;
	
	/**
	 * @param bandwidth
	 * @param latency
	 * @param put
	 * @param get
	 * @param length
	 */
	public CommChannel(final String name, final String core, final URI fileURI, final int bandwidth, final int latency, 
			final String put, final String get, final String empty, final String sinkProc, final String chanMtx) {
		this.setName(name);
		this.core = core;
		this.setFileURI(fileURI);
		this.bandwidth = bandwidth;
		this.latency = latency;
		this.put = put;
		this.get = get;
		this.empty = empty;
		this.sinkProc = sinkProc;
		this.chanMtx = chanMtx;
	}
	public static CommChannel create(String n, String ct, URI f, int bw, int lat, String p, String g, String e, String sp, String cm) {
		return new CommChannel(n, ct, f, bw, lat, p, g, e, sp, cm);
	}
	/**
	 * @return the bandwidth
	 */
	public int getBandwidth() {
		return bandwidth;
	}
	/**
	 * @return the get
	 */
	public String getGet() {
		return get;
	}
	/**
	 * @return the latency
	 */
	public int getLatency() {
		return latency;
	}
	/**
	 * @return the put
	 */
	public String getPut() {
		return put;
	}
	/**
	 * @return the empty
	 */
	public String getEmpty() {
		return empty;
	}
	/**
	 * @return the core
	 */
	public String getCore() {
		return core;
	}
	/**
	 * @return the sinkProc
	 */
	public String getSinkProc() {
		return sinkProc;
	}
	public void generateIncludes(PrintStream file) {
		file.println("#include \"lc_" + this.getName() + "_CommChannel.h\"");
	}
	/* (non-Javadoc)
	 * @see syscomp.entities.Entity#generateCode()
	 */
	@Override
	public void generateCode(CodeGenerator cg) {
		String filename = "lc_" + this.getName() + "_CommChannel.h";
		FileOutputStream out = null;
		PrintStream file = null;
		try {
		    out = new FileOutputStream(filename);
		    file = new PrintStream(out);
		}
		catch (FileNotFoundException e) {
		    System.err.println("Specified file " + filename + " does not exist.");
		    System.exit(1);
		}

		// Print guards
		file.println("#ifndef LC_" + this.getName().toUpperCase() + "_H_");
		file.println("#define LC_" + this.getName().toUpperCase() + "_H_");
		file.println();

		Mutex mtx = (Mutex)cg.lookupName(this.chanMtx);
		
		// Print standard header info
		file.println("#include <assert.h>");
		file.println("#include <lagniappe/CommChannel.h>");
		file.println("#include \"" + mtx.getFileURI().toString() + "\"");
		file.println();
		
		file.println("#include \"" + this.getFileURI() + "\"");
		file.println();
		
		// Start class definition
		file.println("class " + this.getName() + " : public lagniappe::CommChannel, " + mtx.getCore() + " {");

		// private member variables
		file.println("private:");
		file.println("\t" + this.core + " coreQueue;");
		file.println("\tvoid incCount(const lagniappe::RCon * rcon) {lock(); count++; totalCount++; unlock();}");
		file.println("\tvoid decCount(const lagniappe::RCon * rcon) {lock(); count--; unlock();}");
		
		// public method definitions
		file.println("public:");
		
		file.println("\t" + this.getName() + "() : CommChannel(0,0) {}");
		file.println("\tvirtual ~" + this.getName() + "() {}");

		// queue access
		file.println("\tvirtual void put(lagniappe::RCon * rcon) {assert(rcon != NULL); assert(&coreQueue != NULL); incCount(rcon); coreQueue." + this.put + "(rcon);}");
		file.println("\tvirtual lagniappe::RCon * get() {lagniappe::RCon * rcon = coreQueue." + this.get + "(); decCount(rcon); return rcon;}");
		file.println("\tvirtual bool empty() {return coreQueue." + this.empty + "();}");
		//file.println("\tvirtual int getLength() {return coreQueue." + this.length + "();}");
		
		// Close class definition
		
		file.println("};");
		
		// Close guards
		file.println("#endif");
		file.println();
		
	}
}
